package com.example.entity;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.Consumer;

/**
 * 用于DTO快速转换VO实现，只需将DTO类继承此类即可使用
 */
public interface BaseData {
    /**
     * 将当前对象转换为指定视图类的实例，并执行自定义操作
     * 此方法提供了一种机制，将当前对象转换为另一个类的视图（通常用于UI或特定展示层），
     * 并在转换后立即对视图对象执行一个操作，这个操作由消费者接口定义
     *
     * @param <V> 视图对象的类型
     * @param clazz 视图类的Class对象，用于指定转换的目标类型
     * @param consumer 一个消费者接口，定义了在转换后对视图对象执行的操作
     * @return 转换后的视图对象实例
     */
    default <V> V asViewObject(Class<V> clazz, Consumer<V> consumer) {
        // 将当前对象转换为指定视图类的实例
        V v = this.asViewObject(clazz);
        // 对转换后的视图对象执行自定义操作
        consumer.accept(v);
        // 返回转换后的视图对象
        return v;
    }

    /**
     * 创建指定的VO类并将当前DTO对象中的所有成员变量值直接复制到VO对象中
     * @param clazz 指定VO类型
     * @return 指定VO对象
     * @param <V> 指定VO类型
     */
    default <V> V asViewObject(Class<V> clazz) {
        try {
            // 获取VO类的所有成员变量
            Field[] fields = clazz.getDeclaredFields();
            // 获取VO类的无参构造函数
            Constructor<V> constructor = clazz.getConstructor();
            // 实例化VO对象
            V v = constructor.newInstance();
            // 遍历成员变量，将DTO中的值复制到VO中
            Arrays.asList(fields).forEach(field -> convert(field, v));
            return v;
        } catch (ReflectiveOperationException exception) {
            // 日志记录反射操作异常
            Logger logger = LoggerFactory.getLogger(BaseData.class);
            logger.error("在VO与DTO转换时出现了一些错误", exception);
            // 抛出运行时异常，包含原始异常信息
            throw new RuntimeException(exception.getMessage());
        }
    }

    /**
     * 内部使用，快速将当前类中目标对象字段同名字段的值复制到目标对象字段上
     * @param field 目标对象字段
     * @param target 目标对象
     */
    private void convert(Field field, Object target){
        try {
            // 获取当前类中与目标对象字段同名的字段
            Field source = this.getClass().getDeclaredField(field.getName());
            // 设置目标对象字段可访问，以复制值
            field.setAccessible(true);
            // 设置当前类中同名字段可访问，以获取值
            source.setAccessible(true);
            // 将当前类中同名字段的值复制到目标对象字段上
            field.set(target, source.get(this));
        } catch (IllegalAccessException | NoSuchFieldException ignored) {
            // 忽略访问异常和字段不存在异常
        }
    }
}
